#include "clib_stack.h"
#include "clib_sock.h"
#include <rte_malloc.h>
#include "clib_tuple_hash.h"
#include "clib_net_def.h"
#include "clib_stack_malloc.h"
#include "clib_stack_conf.h"
#include <pthread.h>

stack_conf_t stack_cfg;

clib_stack_t l4_satck;

static __thread i32_t clib_stack_idx = -1;

void clib_stack_index_set(i32_t idx) 
{
    clib_stack_idx = idx;
}

i32_t clib_stack_index_get()
{
    return clib_stack_idx;
}

// static void  
// clib_stack_ctx_init(stack_ctx_t* ctx) 
// {
//     clib_queue_init(&ctx->wait_list);
//     clib_queue_init(&ctx->timeout_list);
//     clib_queue_init(&ctx->free_list);
//     clib_queue_init(&ctx->conn_list);
//     clib_queue_init(&ctx->ack_list);
//     clib_queue_init(&ctx->send_list);
//     clib_queue_init(&ctx->rset_list);
//     clib_queue_init(&ctx->close_list);
//     //TODO hash查找算法
//     //ctx->hash_table = clib_tuple_hash_table_create();
//     ctx->sock_n = 0;
//     ctx->free_n = 0;
//     ctx->conn_n = 0;
//     ctx->ack_n  = 0;
//     ctx->send_n = 0;
//     ctx->rset_n = 0;

// }

clib_stack_t* 
clib_stack_create(i32_t sock_n, i32_t ctx_n, i32_t ifnet_n, i32_t socket_id)
{
    i32_t sock_nums = 0;
    clib_stack_t *stack;
    char type[64] = {0};
    snprintf(type,sizeof(type),"l4_clib_stack_%d_%d",ctx_n,ifnet_n);
    if(sock_n <= 0 || ifnet_n < 0) {
        return NULL;
    }
    stack = clib_stack_malloc(type,sizeof(clib_stack_t), CLIB_ALIGN_SIZE, socket_id);
    if(!stack) {
        return NULL;
    }
    memset(stack, 0, sizeof(clib_stack_t));
    
    snprintf(type,sizeof(type),"stack_sock_%d_%d",ctx_n,ifnet_n);
    stack->sock_table = clib_stack_malloc(type,sizeof(clib_sock_t) * sock_n, CLIB_ALIGN_SIZE, socket_id);
    if(!stack->sock_table) {
        clib_stack_free(stack);
        return NULL;
    }
    memset(stack->sock_table, 0, sizeof(clib_sock_t) * sock_n);
    stack->ctx_n = ctx_n;
    stack->ifnet = ifnet_n;
    sock_nums = sock_n / ctx_n;

    clib_sock_t *sk;
    for (int i = 0; i < sock_n; i++) {
        sk = &((clib_sock_t*)stack->sock_table)[i];
        clib_sock_init(sk,i);
    }
    
    for (int i = 0; i < ctx_n; i++) {
        stack_ctx_t* ctx = &stack->ctx[i];
        ctx->ctx_idx = i;
        ctx->sock_n  =  sock_nums;
        /** TODO stack ctx init **/
        ctx->sock_table = &((clib_sock_t*)stack->sock_table)[i * sock_nums];
        ctx->socket_id  = socket_id;
    }

    return stack;
}

void
clib_stack_ctx_init(stack_ctx_t* ctx)
{
    clib_sock_t* sock;
    clib_queue_init(&ctx->wait_list);
    clib_queue_init(&ctx->timeout_list);
    clib_queue_init(&ctx->free_list);
    clib_queue_init(&ctx->conn_list);
    clib_queue_init(&ctx->ack_list);
    clib_queue_init(&ctx->send_list);
    clib_queue_init(&ctx->rset_list);
    clib_queue_init(&ctx->close_list);
    clib_queue_init(&ctx->acpt_list);
    clib_queue_init(&ctx->rto_list);
    clib_queue_init(&ctx->wack_list);
    
    for (int i = 0; i < ctx->sock_n; i++)
    {
        sock = &((clib_sock_t*)ctx->sock_table)[i];
        clib_queue_add(&ctx->free_list,&sock->list);
    }
    
}
// i32_t 
// clib_stack_init(i32_t sock_n, i32_t ctx_n, i32_t ifnet_n, i32_t socket_id)
// {
//     char name[32];
//     snprintf(name,sizeof(name),"l4_stack_%d_%d",ctx_n,ifnet_n);
//     if(sock_n <= 0 || ifnet_n < 0) {
//         return rn_error;
//     }
//     clib_stack_t* stack = &l4_satck;
//     stack->sock_table = clib_stack_malloc(name,sizeof(clib_sock_t) * sock_n, CLIB_ALIGN_SIZE,socket_id);
//     if(!stack->sock_table) {
//         return rn_error;
//     }
//     stack->sock_n = sock_n;
//     stack->ctx_n  = ctx_n;
//     for(int i = 0; i < ctx_n; i++) {
//         stack->ctx[i].socket_id = socket_id;
//         stack->ctx[i].ifnet_n = ifnet_n;
//         stack->ctx[i].sock_table = stack->sock_table;
//         clib_stack_ctx_init(&stack->ctx);
//     }
//     int idx;
//     clib_sock_t* sock;
//     stack_ctx_t *ctx;
//     for(int i = 0; i < sock_n; i++)
//     {
//         idx = i % ctx_n;
//         sock = &((clib_sock_t*)stack->sock_table)[i];
//         sock->sock_id = i;
//         sock->core_id = idx;
//         ctx = &stack->ctx[i];
//         clib_queue_init(&sock->list);
//         clib_queue_insert_tail(&ctx->free_list,&sock->list);
//         ctx->sock_n++;
//     }
//     return rn_ok;
// }

stack_ctx_t* 
clib_get_stack_ctx(clib_stack_t* stack, i32_t queue)
{
    if(queue >=0 && queue < stack->ctx_n) {
        return &stack->ctx[queue];
    }
    return NULL;
}

clib_stack_t* 
clib_get_stack()
{
    return &l4_satck;
}

stack_ctx_t* 
clib_get_stack_ctx(i32_t ifidx)
{
    if(ifidx >= l4_satck.ctx_n) {
        return NULL;
    }
    return &l4_satck.ctx[ifidx];
}

clib_sock_t*
clib_get_sock_new_by_stack(stack_ctx_t* ctx)
{
    clib_queue_t *next;
    next = clib_queue_next(&ctx->free_list);
    if(!next || next == clib_queue_sentinel(&ctx->free_list)) {
        return NULL;
    }

    clib_queue_del(next);

    return (clib_sock_t*)next;
}

clib_sock_t*
clib_get_sock_by_id(clib_stack_t* stack,i32_t sfd)
{
    clib_sock_t *sock;
    stack_ctx_t *ctx;
    i32_t idx;
    idx  = sfd / ctx->sock_n;
    sfd  = sfd % ctx->sock_n;
    ctx  = &stack->ctx[idx];
    sock = (clib_sock_t *)&ctx->sock_table[sfd];
    return sock;
}

void
clib_put_sock_to_stack(stack_ctx_t* ctx, clib_sock_t* sock)
{
    /** TODO sock clean **/
    clib_queue_init(&sock->list);
    clib_queue_insert_tail(&ctx->free_list, &sock->list);
}

i32_t
clib_stack_set_netif(clib_stack_t* stack,stack_netif_t  *netif,i32_t idx)
{
    if (idx >= CLIB_CTX_NUM) {
        return -1;
    }
    
    for(i32_t i = 0; i < stack->ctx_n; i++) 
    {
        stack->ctx[i].netif[idx] = netif;
    }

    return 0;
}